<?php
/**
 * CreateUser: zlh
 * CreateTime: 2022/1/18 19:48
 * Remark:该类主要用来处理钉钉审批流的相关功能
 */

namespace App\Tools\DingTalk;

use AlibabaCloud\SDK\Dingtalk\Vworkflow_1_0\Models\TerminateProcessInstanceHeaders;
use AlibabaCloud\SDK\Dingtalk\Vworkflow_1_0\Models\TerminateProcessInstanceRequest;
use App\Consts\DingTalkConsts\DingTalkConfigConsts;
use App\Consts\ResponseConsts\ResponseStatusConsts;
use App\Func\AppFunc;
use App\Func\ResponseFunc;
use App\Models\System\ConfigModel;
use App\Tools\DingTalk\DingTalkCover\DingTalkCoverBasic;
use App\Tools\DingTalk\DingTalkCover\DingTalkVDrive1_0CoverBasic;
use Exception;
use FileInfo;
use GrantCspaceRequest;
use GrantCspaceRequestV2;
use Illuminate\Http\Exceptions\HttpResponseException;
use OapiCallBackRegisterCallBackRequest;
use OapiProcessDentryAuthRequest;
use OapiProcessGettodonumRequest;
use OapiProcessinstanceCreateRequest;
use OapiProcessinstanceCspaceInfoRequest;
use OapiProcessinstanceFileUrlGetRequest;
use OapiProcessinstanceGetRequest;
use AlibabaCloud\SDK\Dingtalk\Vworkflow_1_0\Models\QuerySchemaByProcessCodeHeaders;
use AlibabaCloud\SDK\Dingtalk\Vworkflow_1_0\Models\QuerySchemaByProcessCodeRequest;

use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;

class DingTalkApprovalProcess extends BaseDingTalk
{
    use NewDingTalkBasic , DingTalkCoverBasic ,DingTalkVDrive1_0CoverBasic;

    /**
     * 配置审批流
     * @param array $process
     *  $process = [
     *      'code' => 审批模板  ex:PROC-57A8EB79-BD22-4876-8251-78A04D0A1921
     *      'originatorUserId' => 审批发起人 ex:18888888
     *      'deptId' => 发起人部门 默认-1  ex: -1
     *      'approversV2' => 自定义审批需要传这个字段 模板审批不用传 ex:  { "taskAction_type": 2,"user_ids": "46,47" }
     *      'formComponent' => 审批模板   ex: [   'name' => '申请单位','value' => '总部' ]
     *      不同类型参考  OldDingTalkApprovalService -》sendOldApprovalProcess 98行
     *  ]
     */
    public static function sendOldApprovalProcess(array $process,&$err = "")
    {
        $req = new OapiProcessinstanceCreateRequest;
        $bestUrl = "https://oapi.dingtalk.com/topapi/processinstance/create";
        $req->setAgentId(AppFunc::getDingTalkConfig()::DING_TALK_AGENT_ID);

        // code
        if(!isset($process['code']) || !$process['code']){
            throw new HttpResponseException(ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误,审批主体必须包含模板代码",
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        $req->setProcessCode($process['code']);

        // originatorUserId
        if(!isset($process['originatorUserId']) && !$process['originatorUserId']){
            throw new HttpResponseException(ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误,审批主体必须包含发起人",
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        $req->setOriginatorUserId($process['originatorUserId']);

        // dept
        if(!isset($process['deptId']) || !$process['deptId']){
            throw new HttpResponseException(ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误,审批主体必须包含发起人部门",
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        $req->setDeptId($process['deptId']);

        // approversV2
        if(@$process['approversV2']){
            $approversV2Data = $process['approversV2'];
            $approversV2SendData = [];
            foreach($approversV2Data as $approversV2){
                $approversV2SendData[] = self::setProcessInstanceApproverVo($approversV2['taskActionType'],$approversV2['userIds']);
            }
            $req->setApproversV2($approversV2SendData);
        }

        // formComponent
        if(!isset($process['formComponent'])){
            throw new HttpResponseException(ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误,审批主体必须包含审批模板",
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        $formComponentData = $process['formComponent'];
        $formComponentSendData = [];

        foreach($formComponentData as $formComponent){
            # 如果格式不正确跳过
            if(!isset($formComponent['name']) || !isset($formComponent['value'])){
                continue;
            }
            $formComponentSendData[] = self::setFormComponentValueVo($formComponent['name'],$formComponent['value']);
        }
        $req->setFormComponentValues($formComponentSendData);
        //send
        $process = self::getDingTalkOldClient()->execute($req, self::getAccessToken(),$bestUrl);
//        dd($process);
        # modify by breezeer @2022.08.01 => add approval log flow content to local log file
        #
        #
        app()->gcHelper->gfDebugPrintToLocalFileByDefault(['req'=>$req,'bestUrl'=>$bestUrl,'process'=>$process]);
        if($process->errcode){
            $err = $process->errmsg;
        }
        return $process->process_instance_id;

    }

    /**
     * 查看用户有多少个待审批
     * @param int $userId
     * @return int
     */
    public static function getUserApprovalProcessCount(string $userId) :int{
        $req = new OapiProcessGettodonumRequest;
        $req->setUserid($userId);
        $bestUrl = "https://oapi.dingtalk.com/topapi/process/gettodonum";
        try {
            $processCount = self::getDingTalkOldClient()->execute($req, self::getAccessToken(),$bestUrl);
        }
        catch (Exception $err) {
            throw new HttpResponseException( ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误".$err->getMessage(),
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        return $processCount->count;
    }

    /**
     * 获取钉钉审批实例
     * @param string $processId
     * @return \$1|false|mixed|\ResultSet|\SimpleXMLElement
     */
    public static function getContractApprovalProcessInfo(string $processId){
        $req = new OapiProcessinstanceGetRequest;
        $req->setProcessInstanceId($processId);
        $bestUrl = "https://oapi.dingtalk.com/topapi/processinstance/get";
        try {
            $processCount = self::getDingTalkOldClient()->execute($req, self::getAccessToken(),$bestUrl);
        }
        catch (Exception $err) {
            throw new HttpResponseException( ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误".$err->getMessage(),
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        return $processCount;
    }

    public static function getApprovalSpaceId(){
        $req = new OapiProcessinstanceCspaceInfoRequest;
        $configModel =  new ConfigModel();
        $userId = $configModel->getConfigByKey("dingTalkDownloadFileUserId",['value'])['value'];
        $req->setUserId($userId);
        $req->setAgentId(AppFunc::getDingTalkConfig()::DING_TALK_AGENT_ID);
        $bestUrl = "https://oapi.dingtalk.com/topapi/processinstance/cspace/info";
        try {
            $res = self::getDingTalkOldClient()->execute($req, self::getAccessToken(),$bestUrl);
        }
        catch (Exception $err) {
            throw new HttpResponseException( ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误".$err->getMessage(),
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        return $res->result->space_id;
    }

    // 授权
    public static function getApprovalFileAuth($fileId){
        $configModel =  new ConfigModel();
        $userId = $configModel->getConfigByKey("dingTalkDownloadFileUserId",['value'])['value'];
        $req = new OapiProcessDentryAuthRequest;
        $request = new GrantCspaceRequestV2;
        $req->setRequest($request);
        $bestUrl = "https://oapi.dingtalk.com/topapi/process/dentry/auth";
        $file_infos = new FileInfo;
        $file_infos->space_id=  self::getApprovalSpaceId();;
        $file_infos->file_id= $fileId;
        $request->file_infos = array($file_infos);
        $request->userid = 60453713692023;
        $res = self::getDingTalkOldClient()->execute($req, self::getAccessToken(),$bestUrl);
    }

    /**
     * 文件下载
     * @param $fileId
     * @param $processId
     * @return \$1|false|mixed|\ResultSet|\SimpleXMLElement
     */
    public static function downApprovalProcessFile($fileId,$processId){
        # 获取文件下载授权
        self::getApprovalFileAuth($fileId);
        $req = new OapiProcessinstanceFileUrlGetRequest;
        $request = new GrantCspaceRequest;
        $request->process_instance_id = $processId;
        $request->file_id = $fileId;
        $req->setRequest($request);
        $bestUrl = "https://oapi.dingtalk.com/topapi/processinstance/file/url/get";
        try {
            $res = self::getDingTalkOldClient()->execute($req, self::getAccessToken(),$bestUrl);
        }
        catch (Exception $err) {
            throw new HttpResponseException( ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误".$err->getMessage(),
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        return $res;
    }

    /**
     * 注册回调
     * @param $url
     * @return \$1|false|mixed|\ResultSet|\SimpleXMLElement
     */
    protected static function setCallBackRegister($url){
        $req = new OapiCallBackRegisterCallBackRequest();
        $bestUrl = "https://oapi.dingtalk.com/call_back/register_call_back";
        // 注册回调事件
        $req->setCallBackTag("['bpms_task_change','bpms_instance_change']");
        $req->setToken("['bpms_task_change','bpms_instance_change']");
        $req->setAesKey("'pqVLdEpfsNtU4wDfJdceJuSMFpRIMe8wUrLMFE3uI6t'");
        $req->setUrl($url);
        try {
            $processCount = self::getDingTalkOldClient()->execute($req, self::getAccessToken(),$bestUrl);
        }
        catch (Exception $err) {
            throw new HttpResponseException( ResponseFunc::returnJson(
                'error',
                '',
                "钉钉客户端错误".$err->getMessage(),
                ResponseStatusConsts::INTERNAL_SERVER_ERROR_500_RESPONSE_STATUS
            ));
        }
        return $processCount;
    }


    public static function getApprovalSchema(){
        $client = self::getDingTalkCoverClient();
        $querySchemaByProcessCodeHeaders = new QuerySchemaByProcessCodeHeaders([]);
        $token =  (string)self::getAccessToken();
        $querySchemaByProcessCodeHeaders->xAcsDingtalkAccessToken = $token;
        $querySchemaByProcessCodeRequest = new QuerySchemaByProcessCodeRequest([
            "processCode" => "PROC-B16E0BA9-BD03-4582-92D5-27C5E05D3A8A"
        ]);
        $res = $client->querySchemaByProcessCodeWithOptions($querySchemaByProcessCodeRequest, $querySchemaByProcessCodeHeaders, new RuntimeOptions([]));
        dd($res);
    }

    public static function approvalTerminate($processId){
        $client = self::getCreateClient();
        $terminateProcessInstanceHeaders = new TerminateProcessInstanceHeaders([]);
        $token =  (string)self::getAccessToken();
        $terminateProcessInstanceHeaders->xAcsDingtalkAccessToken = $token;
        $terminateProcessInstanceRequest = new TerminateProcessInstanceRequest([
            "isSystem" => true,
            "processInstanceId" => $processId
        ]);
        try {
            $client->terminateProcessInstanceWithOptions($terminateProcessInstanceRequest, $terminateProcessInstanceHeaders, new RuntimeOptions([]));
            return true;
        }catch (Exception $exception){
            return false;
        }
    }
}